#include "stdbool.h"
#include "stdio.h"
#include "softspi.h"

#define USE_EXCEL 0
#define USE_DIFFERENCE 0
extern void SoftSpiGpioInit(void);
extern void SckSetValue(bool value);
extern void MosiSetValue(bool value);
extern bool MisoGetValue(void);
extern void NssSetValue(bool value);

extern void delay_ms(uint16_t nms);
extern void ResetSetValue(bool value);
extern void CommandSetValue(bool value);

typedef struct  
{										    
	uint16_t width;			
	uint16_t height;		
	uint16_t id;			
	uint8_t  dir;				
	uint16_t	 wramcmd;	
	uint16_t  setxcmd;		
	uint16_t  setycmd;		
}_lcd_dev; 	

_lcd_dev lcddev;

void ST7735_Reset(void)
{
	ResetSetValue(0);
	delay_ms(100);
	ResetSetValue(1);
	delay_ms(120);
}

void MySPI_W_SS(bool BitValue)
{
		NssSetValue(BitValue);
}

void MySPI_W_SCK(bool BitValue)
{
		SckSetValue(BitValue);
}

void MySPI_W_MOSI(bool BitValue)
{
		MosiSetValue(BitValue);
}

bool MySPI_R_MISO(void)
{
		return MisoGetValue();
}


void MySPI_Init(void)
{
	SoftSpiGpioInit();
	MySPI_W_SS(1);
	MySPI_W_SCK(0);
}

void MySPI_Start(void){
	MySPI_W_SS(0);
}

void MySPI_Stop(void)
{
	MySPI_W_SS(1);
}
extern void LpspiWriteDataBlocking(uint8_t* data,uint32_t datasize);

void SPIWrite(uint8_t dat)
{
    uint8_t data = dat;
//    MySPI_Start();//CS 0
//    uint8_t i = 0;
//    for(;i<8;i++)
//    {
//        MySPI_W_SCK(0);
//        
//        if(dat & 0x80)
//        {
//            MySPI_W_MOSI(1);
//        }else{
//            MySPI_W_MOSI(0);
//        }
//        dat <<= 1;
//        MySPI_W_SCK(1);
//    }
//    MySPI_Stop();
//    while(1)
//    {
//        LpspiWriteDataBlocking(&data,1);
//    }
    LpspiWriteDataBlocking(&data,1);
}

void SPIWriteCmd(uint8_t cmd)
{
	CommandSetValue(0);
	SPIWrite(cmd);
}

void SPIWriteData(uint8_t data)
{
	CommandSetValue(1);
    SPIWrite(data);
}

void Delay_ms(unsigned int n)
{
	unsigned int  i,j;
	for(i=0;i<n;i++)
		for(j=0;j<123;j++);
}

void Lcd_SetRegion(unsigned int x_start,unsigned int y_start,unsigned int x_end,unsigned int y_end)
{		
	SPIWriteCmd(0x2a);
	SPIWriteData(0x00);
	SPIWriteData(x_start+2);
	SPIWriteData(0x00);
	SPIWriteData(x_end+2);

	SPIWriteCmd(0x2b);
	SPIWriteData(0x00);
	SPIWriteData(y_start+3);
	SPIWriteData(0x00);
	SPIWriteData(y_end+3);
	
	SPIWriteCmd(0x2c);
}


void lcd_write_16bit(uint16_t data)
{	
   SPIWriteData(data>>8);
   SPIWriteData(data);
}

void LCD_WriteRAM_Prepare(void)
{
	SPIWriteCmd(lcddev.wramcmd);
}



/*************************************************
º¯ÊýÃû£ºLCD_SetWindows
¹¦ÄÜ£ºÉèÖÃlcdÏÔÊ¾´°¿Ú£¬ÔÚ´ËÇøÓòÐ´µãÊý¾Ý×Ô¶¯»»ÐÐ
Èë¿Ú²ÎÊý£ºxyÆðµãºÍÖÕµã
·µ»ØÖµ£ºÎÞ
*************************************************/
void LCD_SetWindows(uint16_t xStar, uint16_t yStar,uint16_t xEnd,uint16_t yEnd)
{
#if USE_HORIZONTAL==1	//Ê¹ÓÃºáÆÁ
	SPIWriteCmd(lcddev.setxcmd);	
	SPIWriteData(xStar>>8);
	SPIWriteData(0x00FF&xStar+3);		
	SPIWriteData(xEnd>>8);
	SPIWriteData(0x00FF&xEnd+3);

	SPIWriteCmd(lcddev.setycmd);	
	SPIWriteData(yStar>>8);
	SPIWriteData(0x00FF&yStar+2);		
	SPIWriteData(yEnd>>8);
	SPIWriteData(0x00FF&yEnd+2);	
#else
	SPIWriteCmd(lcddev.setxcmd);	
	SPIWriteData(xStar>>8);
	SPIWriteData(0x00FF&xStar+2);		
	SPIWriteData(xEnd>>8);
	SPIWriteData(0x00FF&xEnd+2);

	SPIWriteCmd(lcddev.setycmd);	
	SPIWriteData(yStar>>8);
	SPIWriteData(0x00FF&yStar+3);		
	SPIWriteData(yEnd>>8);
	SPIWriteData(0x00FF&yEnd+3);	
#endif

	LCD_WriteRAM_Prepare();	//¿ªÊ¼Ð´ÈëGRAM				
}   

/*************************************************
º¯ÊýÃû£ºLCD_SetCursor
¹¦ÄÜ£ºÉèÖÃ¹â±êÎ»ÖÃ
Èë¿Ú²ÎÊý£ºxy×ø±ê
·µ»ØÖµ£ºÎÞ
*************************************************/
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{	  	    			
	LCD_SetWindows(Xpos,Ypos,Xpos,Ypos);
} 

void LCD_WriteReg(uint16_t LCD_Reg, uint16_t LCD_RegValue)
{	
	SPIWriteCmd(LCD_Reg);  
	SPIWriteData(LCD_RegValue);	    		 
}	

void LCD_SetParam(void)
{ 	
	lcddev.wramcmd=0x2C;
#if USE_HORIZONTAL==1	//Ê¹ÓÃºáÆÁ	  
	lcddev.dir=1;//ºáÆÁ
	lcddev.width=128;
	lcddev.height=128;
	lcddev.setxcmd=0x2A;
	lcddev.setycmd=0x2B;			
	LCD_WriteReg(0x36,0xA8);

#else//ÊúÆÁ
	lcddev.dir=0;//ÊúÆÁ				 	 		
	lcddev.width=128;
	lcddev.height=128;
	lcddev.setxcmd=0x2A;
	lcddev.setycmd=0x2B;	
	LCD_WriteReg(0x36,0xC8);
#endif
}	

void LCD_Clear(uint16_t Color)
{
	uint16_t i,j;      
	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);	  
	for(i=0;i<lcddev.width;i++)
	{
		for(j=0;j<lcddev.height;j++)
		lcd_write_16bit(Color);	//Ð´ÈëÊý¾Ý 	 
	}
}

void LCD_Init(void)
{
	ST7735_Reset();
	SPIWriteCmd(0x11);
	delay_ms(120);//120ms
	
	//ST7735R Frame Rate
	SPIWriteCmd(0xB1); 
	SPIWriteData(0x01); 
	SPIWriteData(0x2C); 
	SPIWriteData(0x2D); 

	SPIWriteCmd(0xB2); 
	SPIWriteData(0x01); 
	SPIWriteData(0x2C); 
	SPIWriteData(0x2D); 

	SPIWriteCmd(0xB3); 
	SPIWriteData(0x01); 
	SPIWriteData(0x2C); 
	SPIWriteData(0x2D); 
	SPIWriteData(0x01); 
	SPIWriteData(0x2C); 
	SPIWriteData(0x2D); 
	
	SPIWriteCmd(0xB4); //Column inversion 
	SPIWriteData(0x07); 
	
	//ST7735R Power Sequence
	SPIWriteCmd(0xC0); 
	SPIWriteData(0xA2); 
	SPIWriteData(0x02); 
	SPIWriteData(0x84); 
	SPIWriteCmd(0xC1); 
	SPIWriteData(0xC5); 

	SPIWriteCmd(0xC2); 
	SPIWriteData(0x0A); 
	SPIWriteData(0x00); 

	SPIWriteCmd(0xC3); 
	SPIWriteData(0x8A); 
	SPIWriteData(0x2A); 
	SPIWriteCmd(0xC4); 
	SPIWriteData(0x8A); 
	SPIWriteData(0xEE); 
	
	SPIWriteCmd(0xC5); //VCOM 
	SPIWriteData(0x0E); 
	
	SPIWriteCmd(0x36); //MX, MY, RGB mode 
	SPIWriteData(0xC8); 
	
	//ST7735R Gamma Sequence
	SPIWriteCmd(0xe0); 
	SPIWriteData(0x0f); 
	SPIWriteData(0x1a); 
	SPIWriteData(0x0f); 
	SPIWriteData(0x18); 
	SPIWriteData(0x2f); 
	SPIWriteData(0x28); 
	SPIWriteData(0x20); 
	SPIWriteData(0x22); 
	SPIWriteData(0x1f); 
	SPIWriteData(0x1b); 
	SPIWriteData(0x23); 
	SPIWriteData(0x37); 
	SPIWriteData(0x00); 	
	SPIWriteData(0x07); 
	SPIWriteData(0x02); 
	SPIWriteData(0x10); 

	SPIWriteCmd(0xe1); 
	SPIWriteData(0x0f); 
	SPIWriteData(0x1b); 
	SPIWriteData(0x0f); 
	SPIWriteData(0x17); 
	SPIWriteData(0x33); 
	SPIWriteData(0x2c); 
	SPIWriteData(0x29); 
	SPIWriteData(0x2e); 
	SPIWriteData(0x30); 
	SPIWriteData(0x30); 
	SPIWriteData(0x39); 
	SPIWriteData(0x3f); 
	SPIWriteData(0x00); 
	SPIWriteData(0x07); 
	SPIWriteData(0x03); 
	SPIWriteData(0x10);  
	
	SPIWriteCmd(0x2a);
	SPIWriteData(0x00);
	SPIWriteData(0x00+2);
	SPIWriteData(0x00);
	SPIWriteData(0x80+2);

	SPIWriteCmd(0x2b);
	SPIWriteData(0x00);
	SPIWriteData(0x00+3);
	SPIWriteData(0x00);
	SPIWriteData(0x80+3);
	
	SPIWriteCmd(0xF0); //Enable test command  
	SPIWriteData(0x01); 
	SPIWriteCmd(0xF6); //Disable ram power save mode 
	SPIWriteData(0x00); 
	
	SPIWriteCmd(0x3A); //65k mode 
	SPIWriteData(0x05); 
	
	
	SPIWriteCmd(0x29);//Display on
	
	LCD_SetParam();

}

int32_t Disp0_DrawBitmap(uint32_t x, uint32_t y, uint32_t width, uint32_t height, const uint8_t *bitmap)
{
	LCD_SetWindows(x,y,(x+width),(y+height));
	for(uint32_t i=0;i<height-1;i++)
	{
		for(uint32_t j=0;j<width-1;j++)
		{
			SPIWriteData(bitmap[2*(i*width+j*height)]);	 
			SPIWriteData(bitmap[2*(i*width+j*height)+1]);	
		}
	}
	return 0;
}

void st7735_test(void)
{
		
	LCD_Init();	   
	LCD_Clear(0xffff); 
	
	while(1)
	{
		LCD_Clear(0x8000);
		delay_ms(100);
		LCD_Clear(0x01f0);
		delay_ms(100);
	}
}